/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package technotheist.imgcog.filter;

import java.util.Arrays;

import com.amd.aparapi.Device;
import com.amd.aparapi.OpenCL;
import com.amd.aparapi.OpenCLDevice;
import com.amd.aparapi.Range;

public class FFT {
    int len;
    float[] initial;
    float[] real;
    float[] imaginary;
    float[] referenceReal;
    float[] referenceImaginary;
    Range range;
    FFTRunner fft;

    public FFT(int len) {
        this.len = len;
        initial = new float[len];
        real = new float[len];
        imaginary = new float[len];
        referenceReal = Arrays.copyOf(real, real.length);
        referenceImaginary = Arrays.copyOf(imaginary, imaginary.length);
        OpenCLDevice device = (OpenCLDevice) Device.best();
        fft = device.bind(FFTRunner.class);

        for (int i = 0; i < len; i++) {
            initial[i] = real[i] = referenceReal[i] = (float) (Math.random() * 256);
            imaginary[i] = referenceImaginary[0] = 0f;
        }

        range = device.createRange(64);
        fft.forward(range, real, imaginary);
    }
    
    public void transform(float[] src) {
        System.arraycopy(src, 0, initial, 0, len);
        System.arraycopy(src, 0, real, 0, len);
        System.arraycopy(src, 0, referenceReal, 0, len);
        for(int i = 0; i < imaginary.length; i++) {
            imaginary[i] = referenceImaginary[0] = 0f;
        }
        fft.forward(range, real, imaginary);
    }

    @OpenCL.Resource("com/amd/aparapi/sample/extension/fft.cl")
    interface FFTRunner extends OpenCL<FFTRunner> {

        public FFTRunner forward(//
                Range _range,//
                @GlobalReadWrite("real") float[] real,//
                @GlobalReadWrite("imaginary") float[] imaginary//
                );
    }
//
//   static void fft(float[] x, float[] y) {
//      short dir = 1;
//      long m = 10;
//      int n, i, i1, j, k, i2, l, l1, l2;
//      double c1, c2, tx, ty, t1, t2, u1, u2, z;
//
//      /* Calculate the number of points */
//      n = 1;
//      for (i = 0; i < m; i++)
//         n *= 2;
//
//      /* Do the bit reversal */
//      i2 = n >> 1;
//      j = 0;
//      for (i = 0; i < n - 1; i++) {
//         if (i < j) {
//            tx = x[i];
//            ty = y[i];
//            x[i] = x[j];
//            y[i] = y[j];
//            x[j] = (float) tx;
//            y[j] = (float) ty;
//         }
//         k = i2;
//         while (k <= j) {
//            j -= k;
//            k >>= 1;
//         }
//         j += k;
//      }
//
//      /* Compute the FFT */
//      c1 = -1.0;
//      c2 = 0.0;
//      l2 = 1;
//      for (l = 0; l < m; l++) {
//         l1 = l2;
//         l2 <<= 1;
//         u1 = 1.0;
//         u2 = 0.0;
//         for (j = 0; j < l1; j++) {
//            for (i = j; i < n; i += l2) {
//               i1 = i + l1;
//               t1 = u1 * x[i1] - u2 * y[i1];
//               t2 = u1 * y[i1] + u2 * x[i1];
//               x[i1] = (float) (x[i] - t1);
//               y[i1] = (float) (y[i] - t2);
//               x[i] += (float) t1;
//               y[i] += (float) t2;
//            }
//            z = u1 * c1 - u2 * c2;
//            u2 = u1 * c2 + u2 * c1;
//            u1 = z;
//         }
//         c2 = Math.sqrt((1.0 - c1) / 2.0);
//         if (dir == 1)
//            c2 = -c2;
//         c1 = Math.sqrt((1.0 + c1) / 2.0);
//      }
//
//      /* Scaling for forward transform */
//      /*if (dir == 1) {
//         for (i=0;i<n;i++) {
//            x[i] /= n;
//            y[i] /= n;
//         }
//      }*/
//
//   }
}
